"""
Code formatting utilities for C++ code generation.

This module provides utilities for:
- Indentation management
- Comment generation
- Line wrapping
"""

from __future__ import annotations

from typing import Literal


class CodeFormatter:
    """
    Utilities for formatting C++ code.

    Handles indentation, comments, and basic formatting.
    """

    def __init__(
        self,
        indent_style: Literal["spaces", "tabs"] = "spaces",
        indent_width: int = 4,
        max_line_length: int = 100,
    ):
        """
        Initialize code formatter.

        Args:
            indent_style: "spaces" or "tabs"
            indent_width: Number of spaces per indent level (ignored if tabs)
            max_line_length: Maximum line length before wrapping
        """
        self.indent_style = indent_style
        self.indent_width = indent_width
        self.max_line_length = max_line_length

    def indent(self, text: str, level: int = 1) -> str:
        """
        Indent text by the specified level.

        Args:
            text: Text to indent
            level: Indentation level

        Returns:
            Indented text

        Examples:
            >>> formatter = CodeFormatter(indent_style="spaces", indent_width=4)
            >>> formatter.indent("int x;")
            "    int x;"
        """
        if self.indent_style == "tabs":
            indent_str = "\t" * level
        else:
            indent_str = " " * (self.indent_width * level)

        # Handle multi-line text
        lines = text.split("\n")
        indented_lines = [indent_str + line if line.strip() else "" for line in lines]
        return "\n".join(indented_lines)

    def format_comment(self, comment: str, style: Literal["line", "block", "doxygen"] = "line") -> str:
        """
        Format a comment.

        Args:
            comment: Comment text
            style: Comment style ("line" for //, "block" for /* */, "doxygen" for ///)

        Returns:
            Formatted comment

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_comment("This is a comment")
            "// This is a comment"

            >>> formatter.format_comment("This is a comment", style="doxygen")
            "/// This is a comment"
        """
        if not comment:
            return ""

        if style == "line":
            return f"// {comment}"
        elif style == "doxygen":
            return f"/// {comment}"
        elif style == "block":
            return f"/* {comment} */"
        else:
            return f"// {comment}"

    def format_multiline_comment(
        self, comment: str, style: Literal["line", "block", "doxygen"] = "doxygen"
    ) -> str:
        """
        Format a multi-line comment.

        Args:
            comment: Comment text (may contain newlines)
            style: Comment style

        Returns:
            Formatted multi-line comment

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_multiline_comment("Line 1\\nLine 2")
            "/// Line 1\\n/// Line 2"
        """
        lines = comment.strip().split("\n")

        if style == "block":
            if len(lines) == 1:
                return f"/* {lines[0]} */"
            else:
                result = ["/*"]
                for line in lines:
                    result.append(f" * {line}" if line.strip() else " *")
                result.append(" */")
                return "\n".join(result)
        else:
            # Line or doxygen style
            prefix = "/// " if style == "doxygen" else "// "
            return "\n".join(prefix + line for line in lines)

    def format_parameter_list(self, parameters: list[str], indent_level: int = 0) -> str:
        """
        Format a parameter list, wrapping if needed.

        Args:
            parameters: List of parameter strings
            indent_level: Current indentation level

        Returns:
            Formatted parameter list

        Examples:
            >>> formatter = CodeFormatter(max_line_length=80)
            >>> formatter.format_parameter_list(["int x", "int y", "int z"])
            "int x, int y, int z"

            >>> # Long parameters get wrapped
            >>> formatter.format_parameter_list([
            ...     "int very_long_parameter_name",
            ...     "std::string another_very_long_parameter"
            ... ])
            ...
        """
        if not parameters:
            return ""

        # Try single line first
        single_line = ", ".join(parameters)
        current_indent = self.indent_width * indent_level

        if len(single_line) + current_indent <= self.max_line_length:
            return single_line

        # Wrap to multiple lines
        lines = []
        for i, param in enumerate(parameters):
            if i == 0:
                lines.append(param)
            else:
                lines.append(self.indent(param, indent_level + 1))

        return ",\n".join(lines)

    def format_function_signature(
        self,
        return_type: str,
        name: str,
        parameters: list[str],
        const: bool = False,
        noexcept: bool = False,
        override: bool = False,
        pure_virtual: bool = False,
    ) -> str:
        """
        Format a complete function signature.

        Args:
            return_type: Return type
            name: Function name
            parameters: List of parameter strings
            const: Whether the method is const
            noexcept: Whether the method is noexcept
            override: Whether the method is override
            pure_virtual: Whether the method is pure virtual (= 0)

        Returns:
            Formatted function signature

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_function_signature("void", "do_something", ["int x"])
            "void do_something(int x)"

            >>> formatter.format_function_signature(
            ...     "int", "get_value", [], const=True, noexcept=True
            ... )
            "int get_value() const noexcept"
        """
        param_list = ", ".join(parameters) if parameters else ""
        signature = f"{return_type} {name}({param_list})"

        qualifiers = []
        if const:
            qualifiers.append("const")
        if noexcept:
            qualifiers.append("noexcept")
        if override:
            qualifiers.append("override")

        if qualifiers:
            signature += " " + " ".join(qualifiers)

        if pure_virtual:
            signature += " = 0"

        return signature

    def format_class_member(
        self, member_type: str, name: str, initializer: str | None = None
    ) -> str:
        """
        Format a class member declaration.

        Args:
            member_type: Type of the member
            name: Name of the member
            initializer: Optional initializer

        Returns:
            Formatted member declaration

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_class_member("int", "m_count")
            "int m_count;"

            >>> formatter.format_class_member("int", "m_max", "100")
            "int m_max = 100;"
        """
        if initializer:
            return f"{member_type} {name} = {initializer};"
        else:
            return f"{member_type} {name};"

    def format_include(self, header: str, system: bool = False) -> str:
        """
        Format an include directive.

        Args:
            header: Header file name
            system: Whether it's a system header (uses <> instead of "")

        Returns:
            Formatted include directive

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_include("string", system=True)
            "#include <string>"

            >>> formatter.format_include("my_header.hpp")
            '#include "my_header.hpp"'
        """
        if system:
            return f"#include <{header}>"
        else:
            return f'#include "{header}"'

    def format_namespace_open(self, namespace_parts: list[str]) -> str:
        """
        Format namespace opening.

        Args:
            namespace_parts: List of namespace parts (e.g., ["my_app", "services"])

        Returns:
            Formatted namespace opening

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_namespace_open(["my_app", "services"])
            "namespace my_app::services {"
        """
        if not namespace_parts:
            return ""

        namespace = "::".join(namespace_parts)
        return f"namespace {namespace} {{"

    def format_namespace_close(self, namespace_parts: list[str]) -> str:
        """
        Format namespace closing.

        Args:
            namespace_parts: List of namespace parts

        Returns:
            Formatted namespace closing

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_namespace_close(["my_app", "services"])
            "} // namespace my_app::services"
        """
        if not namespace_parts:
            return ""

        namespace = "::".join(namespace_parts)
        return f"}}  // namespace {namespace}"

    def format_access_specifier(self, specifier: str) -> str:
        """
        Format an access specifier.

        Args:
            specifier: Access specifier ("public", "private", "protected")

        Returns:
            Formatted access specifier

        Examples:
            >>> formatter = CodeFormatter()
            >>> formatter.format_access_specifier("public")
            "public:"
        """
        return f"{specifier}:"

    def blank_lines(self, count: int = 1) -> str:
        """
        Generate blank lines.

        Args:
            count: Number of blank lines

        Returns:
            String with blank lines
        """
        return "\n" * count
